package com.zlj.accountant.services;

import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import android.util.Log;

import com.j256.ormlite.dao.RawRowMapper;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;
import com.zlj.accountant.core.HandlerManager;
import com.zlj.accountant.core.ann.Publish;
import com.zlj.accountant.db.dao.DBHelper;
import com.zlj.accountant.db.dao.MainService;
import com.zlj.accountant.db.entity.TBooking;
import com.zlj.accountant.publish.BalanceType;
import com.zlj.accountant.publish.key.GetBookingForMonthGroupKey;
import com.zlj.accountant.publish.key.GetBookingListKey;
import com.zlj.accountant.publish.report.FBookingReport;
import com.zlj.accountant.publish.report.GetBookingReportKey;
import com.zlj.accountant.publish.view.FBooking;
import com.zlj.accountant.publish.view.FBookingForMonthGroup;
import com.zlj.accountant.utils.DateUtils;

public class BookingPubilcService extends MainService<TBooking> {
	
	private static final String tag = "BookingPubilcService";

	public BookingPubilcService(DBHelper dbHelper) {
		super(dbHelper);
	}
	
	private FBooking getFBooking(TBooking t){
        FBooking f = new FBooking();
        f.accountId = t.getAccountId();
        if(t.getBalanceType()==BalanceType.Income){
        	f.amount = t.getIncome();
        }else{
        	f.amount = t.getOutgo();
        }
        f.balanceType = t.getBalanceType();
        f.createTime = t.getCreateTime().getTime();
        f.creator = t.getCreator();
        f.id = t.getId();
        f.notes = t.getNotes();
        f.accountType = t.getAccountType();
        return f;
	}
	
	@Publish
	protected final class GetBookingListByAccountProvider extends OneKeyResultListProvider<FBooking, UUID>{

		@Override
        public void provide(HandlerManager handler, List<FBooking> list,
        		UUID key) throws Exception
        {
	        List<TBooking> l = handler.getList(TBooking.class,key);
	        for(TBooking t : l){
	            list.add(getFBooking(t));
            }
        }		
	}
	
	@Publish
	protected final class GetBookingListProvider extends OneKeyResultListProvider<FBooking, GetBookingListKey>{

		@Override
		public void provide(HandlerManager handler, List<FBooking> list,
				GetBookingListKey key) throws Exception {
			QueryBuilder<TBooking, UUID> query = getDao().queryBuilder();
			Where<TBooking, UUID> where = query.where().between(TBooking.Field_CreateTime, new Date(key.startDate), new Date(key.endDate));
			if(key.accountId!=null){
				where.and().eq(TBooking.Field_AccountId, key.accountId);
			}
			if(key.accoutType!=null){
				where.and().eq(TBooking.Field_AccountType, key.accoutType);
			}
			query.orderBy(TBooking.Field_CreateTime, false);
			for (TBooking t : getDao().query(query.prepare())){
				list.add(getFBooking(t));
			}
		}
	}
	
	@Publish
	protected final class GetBookingReportProvider extends OneKeyResultListProvider<FBookingReport, GetBookingReportKey>{

		@Override
		public void provide(HandlerManager handler,List<FBookingReport> list,
				GetBookingReportKey key) throws Exception {
			StringBuilder sql = new StringBuilder()
					.append(" SELECT ")
					.append(" SUM(T.").append(TBooking.Field_Income).append(") AS INCOME,")
					.append(" SUM(T.").append(TBooking.Field_Outgo).append(") AS OUTGO,")
					.append(" SUM(T.").append(TBooking.Field_Income).append("- T.").append(TBooking.Field_Outgo).append(") AS BALANCE, ")
					.append(" DATETIME(T.").append(TBooking.Field_CreateTime).append(",'start of ").append(key.groupType.name().toLowerCase()).append("')")
					.append(" FROM ").append(TBooking.TableName).append(" AS T ")
					.append(" WHERE ")
					.append(" T.").append(TBooking.Field_CreateTime).append(" > ? ")
					.append(" AND ")
					.append(" T.").append(TBooking.Field_CreateTime).append(" < ? ");
			List<String> param = new ArrayList<String>();
			param.add(DateUtils.dateFormat(key.startDate,DateUtils.DateTime_Format));
			param.add(DateUtils.dateFormat(key.endDate, DateUtils.DateTime_Format));
			if(key.accountId!=null){
				sql.append(" AND T.").append(TBooking.Field_AccountId).append(" = ? ");
				param.add(key.accountId.toString());
			}
			if(key.accoutType!=null){
				sql.append(" AND T.").append(TBooking.Field_AccountType).append(" = ? ");
				param.add(key.accoutType.name());
			}
			sql.append(" GROUP BY DATETIME(T.").append(TBooking.Field_CreateTime).append(",'start of ").append(key.groupType.name().toLowerCase()).append("')");
			Log.i(tag, sql.toString());
			list.addAll(getDao().queryRaw(sql.toString(), new RawRowMapper<FBookingReport>(){

				@Override
				public FBookingReport mapRow(String[] column, String[] result)
						throws SQLException {
					FBookingReport fb = new FBookingReport();
					fb.income = Double.parseDouble(result[0]);
					fb.outgo = Double.parseDouble(result[1]);
					fb.balance = Double.parseDouble(result[2]);
					fb.date = DateUtils.unDateFormat(result[3]);
					return fb;
				}
				
			}, param.toArray(new String[0])).getResults());
		
		}
		
	}
	
	@Publish
	protected final class GetBookingForMonthGroupProvider extends OneKeyResultProvider<FBookingForMonthGroup, GetBookingForMonthGroupKey>{

		@Override
		public FBookingForMonthGroup provide(HandlerManager handler,
				GetBookingForMonthGroupKey key) throws Exception {
			List<FBookingReport> groups = handler.getList(FBookingReport.class,new GetBookingReportKey(key.startDate,key.endDate,key.accountId,key.accoutType));
			List<FBooking> bookings = handler.getList(FBooking.class,new GetBookingListKey(key.startDate,key.endDate,key.accountId,key.accoutType));
			FBookingForMonthGroup result = new FBookingForMonthGroup();
			Map<FBookingReport,List<FBooking>> map = new HashMap<FBookingReport, List<FBooking>>();
			result.dayList = map;
			result.monthReport = groups;
			final String format = "yyyyMM";
			Map<String,FBookingReport> groupMap = new HashMap<String, FBookingReport>();
			for (FBookingReport g : groups) {
				String month = DateUtils.dateFormat(g.date, format);
				groupMap.put(month, g);
			}
			for (FBooking fBooking : bookings) {
				FBookingReport fb = groupMap.get(DateUtils.dateFormat(fBooking.createTime, format));
				if(!map.containsKey(fb)){
					map.put(fb, new ArrayList<FBooking>());
				}
				map.get(fb).add(fBooking);
			}			
			return result;
		}
		
	}
	
}
